package com.breaker.kata.tool.mysql;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.mysql.cj.jdbc.MysqlDataSource;
import lombok.SneakyThrows;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.SQLException;

public class MapperToolWithMybatisPlus {
    private static final SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

    @SneakyThrows
    private static SqlSessionFactory getSqlSessionFactory() {
        if (sqlSessionFactory != null) {
            return sqlSessionFactory;
        }
        DataSource dataSource = getDataSource();
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setConfiguration(getConfiguration(dataSource));
        return factoryBean.getObject();
    }

    public static <T> T getMapper(Class<T> tClass) {
        Configuration configuration = sqlSessionFactory.getConfiguration();
        return configuration.getMapper(tClass, sqlSessionFactory.openSession(true));
    }

    @SneakyThrows
    public static <T, M> T getRepository(Class<T> repositoryClass, Class<M> mapperClass) {
        T repository = repositoryClass.getDeclaredConstructor().newInstance();
        Field field;
        try {
            field = repository.getClass().getDeclaredField("baseMapper");
        } catch (NoSuchFieldException e) {
            field = repository.getClass().getSuperclass().getDeclaredField("baseMapper");
        }
        field.setAccessible(true);
        field.set(repository, getMapper(mapperClass));
        return repository;
    }

    private static MybatisConfiguration getConfiguration(DataSource dataSource) {
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setEnvironment(new Environment("UNPOOLED",
                new JdbcTransactionFactory(), dataSource));
        configuration.addMappers(TestEnvConfig.mysqlPackage);
        return configuration;
    }

    private static DataSource getDataSource() throws SQLException {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUrl(TestEnvConfig.mysqlUrl);
        dataSource.setDatabaseName(TestEnvConfig.mysqlDatabaseName);
        dataSource.setPort(TestEnvConfig.mysqlPort);
        dataSource.setUser(TestEnvConfig.mysqlUserName);
        dataSource.setPassword(TestEnvConfig.mysqlPassword);
        dataSource.setServerTimezone("UTC");
        return dataSource;
    }
}
